import hashlib
import bcrypt
import re
from abc import ABC, abstractmethod

class User(ABC):
    """用户抽象基类"""
    def __init__(self, user_id, username, email, password_hash, avatar_path=None, 
                 security_question=None, security_answer_hash=None, roles=None):
        self.user_id = user_id
        self.username = username
        self.email = email
        self._password_hash = password_hash
        # path to avatar image (can be relative to project cwd or absolute)
        self.avatar_path = avatar_path
        # 安全问题用于密码重置
        self.security_question = security_question
        self.security_answer_hash = security_answer_hash
        
        # 多角色支持
        self.roles = roles or [self.get_role()]  # 默认包含当前角色
        self.current_role = self.get_role()  # 当前激活的角色
    
    @abstractmethod
    def get_role(self):
        pass
    
    def get_roles(self):
        """获取用户所有角色"""
        return self.roles
    
    def has_role(self, role):
        """检查用户是否拥有某个角色"""
        return role in self.roles
    
    def switch_role(self, role):
        """切换当前激活角色"""
        if role in self.roles:
            self.current_role = role
            return True
        return False
    
    def add_role(self, role):
        """添加角色"""
        if role not in self.roles:
            self.roles.append(role)
    
    def remove_role(self, role):
        """移除角色"""
        if role in self.roles and len(self.roles) > 1:
            self.roles.remove(role)
            if self.current_role == role:
                self.current_role = self.roles[0]
    
    def verify_password(self, password):
        """验证密码，支持新的bcrypt和旧的SHA256格式"""
        try:
            # 尝试使用bcrypt验证（新格式）
            return bcrypt.checkpw(password.encode('utf-8'), self._password_hash.encode('utf-8'))
        except (ValueError, TypeError):
            # 如果失败，可能是旧格式的SHA256，进行兼容性验证
            return self._password_hash == self._hash_password_legacy(password)
    
    @staticmethod
    def _hash_password(password):
        """使用bcrypt生成安全的密码哈希"""
        salt = bcrypt.gensalt()
        return bcrypt.hashpw(password.encode('utf-8'), salt).decode('utf-8')
    
    @staticmethod
    def _hash_password_legacy(password):
        """旧的SHA256哈希方法，用于兼容性"""
        return hashlib.sha256(password.encode()).hexdigest()
    
    @staticmethod
    def validate_password_strength(password):
        """验证密码强度
        
        Returns:
            tuple: (is_valid, error_message)
        """
        if not password:
            return False, "Password cannot be empty"
        
        if len(password) < 8:
            return False, "Password must be at least 8 characters long"
        
        if len(password) > 128:
            return False, "Password cannot exceed 128 characters"
        
        # 检查是否包含至少一个字母
        if not re.search(r'[a-zA-Z]', password):
            return False, "Password must contain at least one letter"
        
        # 检查是否包含至少一个数字
        if not re.search(r'\d', password):
            return False, "Password must contain at least one digit"
        
        # 检查是否包含特殊字符
        if not re.search(r'[!@#$%^&*(),.?":{}|<>]', password):
            return False, "Password must contain at least one special character (!@#$%^&* etc.)"
        
        # 检查常见弱密码
        weak_passwords = [
            'password', '123456', '12345678', 'qwerty', 'abc123',
            'password123', 'admin', 'letmein', 'welcome', 'monkey'
        ]
        if password.lower() in weak_passwords:
            return False, "Password is too simple, please choose a more complex password"
        
        return True, "Password meets the requirements"
    
    @staticmethod
    def calculate_password_strength(password):
        """计算密码强度等级
        
        Returns:
            tuple: (strength_level, strength_text, color)
            strength_level: 'weak', 'medium', 'strong'
        """
        if not password:
            return 'weak', 'None', '#95A5A6'
        
        score = 0
        
        # 长度评分
        if len(password) >= 8:
            score += 1
        if len(password) >= 12:
            score += 1
        if len(password) >= 16:
            score += 1
        
        # 包含小写字母
        if re.search(r'[a-z]', password):
            score += 1
        
        # 包含大写字母
        if re.search(r'[A-Z]', password):
            score += 1
        
        # 包含数字
        if re.search(r'\d', password):
            score += 1
        
        # 包含特殊字符
        if re.search(r'[!@#$%^&*(),.?":{}|<>]', password):
            score += 1
        
        # 检查是否是常见弱密码
        weak_passwords = [
            'password', '123456', '12345678', 'qwerty', 'abc123',
            'password123', 'admin', 'letmein', 'welcome', 'monkey'
        ]
        if password.lower() in weak_passwords:
            return 'weak', 'Weak (Common Password)', '#E74C3C'
        
        # 根据得分判断强度
        if score <= 3:
            return 'weak', 'Weak', '#E74C3C'
        elif score <= 5:
            return 'medium', 'Medium', '#F39C12'
        else:
            return 'strong', 'Strong', '#27AE60'
    
    def verify_security_answer(self, answer):
        """验证安全问题答案"""
        if not self.security_answer_hash:
            return False
        try:
            # 尝试使用bcrypt验证（新格式）
            return bcrypt.checkpw(answer.lower().strip().encode('utf-8'), 
                                self.security_answer_hash.encode('utf-8'))
        except (ValueError, TypeError):
            # 如果失败，可能是旧格式的SHA256
            return self.security_answer_hash == hashlib.sha256(
                answer.lower().strip().encode()).hexdigest()
    
    @staticmethod
    def hash_security_answer(answer):
        """对安全问题答案进行哈希（统一转小写并去空格）"""
        normalized_answer = answer.lower().strip()
        salt = bcrypt.gensalt()
        return bcrypt.hashpw(normalized_answer.encode('utf-8'), salt).decode('utf-8')
    
    def to_dict(self):
        # 如果有customer角色，总是保存为customer（确保下次登录默认是用户模式）
        # 如果没有customer角色，则保存当前角色
        role_to_save = 'customer' if 'customer' in self.roles else self.current_role
        
        return {
            'user_id': self.user_id,
            'username': self.username,
            'email': self.email,
            'password_hash': self._password_hash,
            'role': role_to_save,  # 保存默认角色（如果有customer则优先使用customer）
            'roles': self.roles,  # 保存所有角色
            'avatar_path': getattr(self, 'avatar_path', None),
            'security_question': getattr(self, 'security_question', None),
            'security_answer_hash': getattr(self, 'security_answer_hash', None)
        }

class Customer(User):
    def get_role(self):
        return "customer"
    
    def __init__(self, user_id, username, email, password_hash, shipping_address=None, 
                 avatar_path=None, security_question=None, security_answer_hash=None, roles=None):
        super().__init__(user_id, username, email, password_hash, avatar_path=avatar_path,
                        security_question=security_question, security_answer_hash=security_answer_hash,
                        roles=roles)
        self.shipping_address = shipping_address or ""

class Seller(User):
    def get_role(self):
        return "seller"
    
    def __init__(self, user_id, username, email, password_hash, store_name, 
                 avatar_path=None, security_question=None, security_answer_hash=None, roles=None):
        super().__init__(user_id, username, email, password_hash, avatar_path=avatar_path,
                        security_question=security_question, security_answer_hash=security_answer_hash,
                        roles=roles)
        self.store_name = store_name

class Admin(User):
    def get_role(self):
        return "admin"
    
    def __init__(self, user_id, username, email, password_hash, avatar_path=None,
                 security_question=None, security_answer_hash=None, roles=None):
        super().__init__(user_id, username, email, password_hash, avatar_path=avatar_path,
                        security_question=security_question, security_answer_hash=security_answer_hash,
                        roles=roles)